#ifndef SOCKET_HH
#define SOCKET_HH

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <string>
#include <iostream>

#include "saddr.hh"

using namespace std;

#define SOCKET_STATE_CLOSE          -1
#define SOCKET_DFLT_ADDRESS         "127.0.0.1"
#define SOCKET_DFLT_PORT            0
#define SOCKET_DFLT_BACKLOG         128

namespace NM
{
class 	Socket
{
public:
    /**
     * Socket type.
     */
    enum type {UDP4, UDP6, TCP4, TCP6};

public:
    Socket();											/**< Default constructor. */
    Socket(enum Socket::type);                          /**< Construct a socket based on predefined types. */
    Socket(enum Socket::type, const string &, int);     /**< IPv4 TCP socket, with address and port. */
    Socket(const Socket &);                             /**< Construct by copy. */
    Socket &operator=(const Socket &);                  /**< Assignement. */
    bool     operator==(const Socket &);				/**< True if the both instances are the same. */
    bool     operator==(Socket *);						/**< True if the both instances are the same. */
    ~Socket();											/**< Destructor. */

    void 		setType(enum Socket::type);             /**< Set a Socket type. */
    void 		setAddress(const string &);				/**< Set the IP address. */
    void 		setName(const string &);				/**< Set the IP address or hostname. */
    void 		setPort(int);							/**< Set the endpoint port number. */
    void 		setBlock(bool);							/**< true:socket become blockant, false: non-blockant. */
    void 		setBacklog(int);						/**< Set listen's backlog. */
    Saddr 		*getSaddr();							/**< Give access to the internal Saddr class. */

    void 		socket();								/**< Create a socket. */
    void		bind();									/**< Bind to Socket::port. */
    void 		bind(int);								/**< Bind to specified port. */
    void		listen();								/**< Place the socket in listen mode. */
    void		connect();								/**< Connect to Socket::address and Socket::port */
    void 		connect(const string &, int);			/**< Connect to the specified address and port. */
    void 		disconnect();							/**< Close the socket. */
    void 		close();								/**< Close the socket. Synonym to Socket::disconnect(). */
    void 		shutdown(char = 'a');					/**< Shutdown the socket. */
    Socket      *accept();								/**< Accept a connection (blocking). */

    int 		receive(void *, int);					/**< Receive some bytes. */
    int 		receive(int*);							/**< Receive an integer. */
    int 		receiveFrom(void *, int, Saddr &);		/**< Receive some bytes. */
    int 		receiveFrom(int *, Saddr &);			/**< Receive an integer. */

    int 		send(void *, int);						/**< Send some bytes. */
    int 		send(const string &);					/**< Send a string.   */
    int 		send(int);								/**< Send an integer. */
    int 		sendTo(void *, int, Saddr &);			/**< Send some bytes. */
    int 		sendTo(const string &, Saddr &);		/**< Send a string.   */
    int 		sendTo(int, Saddr &);					/**< Send an integer. */

    void 		endpoint();								/**< Create and endpoint using current configuration. */
    void 		endpoint(enum Socket::type,
                         const string &, int);			/**< Create an endpoint using specicied type, address and port. */

private:
    int 				fd;								/**< Socket file descriptor. */
    int 				backlog; 						/**< listen's backlog. */
    enum Socket::type 	type;							/**< Connection type. */
    Saddr 				addr;							/**< IP-version agnostic sockaddr. */

public:
};
}

#endif
